package com.example.task.common;

import com.sun.xml.internal.ws.handler.HandlerException;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.ToString;

import java.io.Serializable;

@ToString
@SuppressWarnings("unused")
public class Result<T> implements Serializable {

    @Getter
    @ApiModelProperty("返回数据,可能为空")
    private T data;

    @Getter
    @ApiModelProperty("状态码")
    private Integer code;

    @Getter
    @ApiModelProperty("消息提示")
    private String msg;

    @Getter
    @ApiModelProperty("请求是否成功")
    private boolean success;

    @Getter
    @ApiModelProperty("总条数")
    private long total;

    @Getter
    @ApiModelProperty("总页数")
    private long pages;

    @Getter
    @ApiModelProperty("异常信息")
    private Throwable throwable;

    @Getter
    @ApiModelProperty("完整堆栈信息")
    private StackTraceElement[] stackTraceElements;

    /**
     * 标识成功的固定状态枚举
     */
    public static final ResultEnum SUCCESS_ENUM = ResultEnum.SUCCESS;
    /**
     * 标识失败的固定状态枚举
     */
    public static final ResultEnum FAILURE_ENUM = ResultEnum.FAILURE;


    public Result() {

    }

    private Result(T data, Integer code, String msg, boolean success, long total, long pages, Throwable throwable) {
        this.data = data;
        this.code = code;
        this.msg = msg;
        this.success = success;
        this.total = total;
        this.pages = pages;
        this.throwable = throwable;
        if (throwable != null) {
            this.stackTraceElements = throwable.getStackTrace();
        }
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 内部采用 {@link ResultEnum#SUCCESS} 的 code 和 msg
     */
    public static <T> Result<T> success() {
        return success(null, SUCCESS_ENUM);
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 内部采用 {@link ResultEnum#SUCCESS} 的 code 和 msg
     *
     * @param data 需要返回的数据
     */
    public static <T> Result<T> success(T data) {
        return success(data, SUCCESS_ENUM);
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 内部采用 {@link ResultEnum#SUCCESS} 的 code 和 msg
     *
     * @param resultEnum 返回状态
     */
    public static <T> Result<T> success(ResultEnum resultEnum) {
        if (resultEnum == null) {
            throw new HandlerException("枚举参数不可为空");
        }
        return success(null, resultEnum.code, resultEnum.msg);
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 内部采用 {@link ResultEnum#SUCCESS} 的 code 和 msg
     *
     * @param data 需要返回的数据
     */
    public static <T> Result<T> success(T data, ResultEnum resultEnum) {
        if (resultEnum == null) {
            throw new HandlerException("枚举参数不可为空");
        }
        return success(data, resultEnum.code, resultEnum.msg);
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 允许用户自定义 code
     * 内部采用 {@link ResultEnum#SUCCESS} 的 msg
     *
     * @param data 需要返回的数据
     */
    public static <T> Result<T> success(T data, int code) {
        return success(data, code, SUCCESS_ENUM.getMsg());
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 允许用户自定义 msg
     * 内部采用 {@link ResultEnum#SUCCESS} 的 code
     *
     * @param data 需要返回的数据
     */
    public static <T> Result<T> success(T data, String message) {
        return success(data, SUCCESS_ENUM.getCode(), message);
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 允许用户自定义 code 和 msg
     *
     * @param code    状态码
     * @param message 消息
     */
    public static <T> Result<T> success(int code, String message) {
        return new Result<>(null, code, message, true, 0, 0, null);
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 允许用户自定义 code 和 msg
     *
     * @param data 需要返回的数据
     */
    public static <T> Result<T> success(T data, int code, String message) {
        return new Result<>(data, code, message, true, 0, 0, null);
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 允许用户自定义 code 和 msg
     *
     * @param data 需要返回的数据
     */
    public static <T> Result<T> success(int code, String message, T data) {
        return new Result<>(data, code, message, true, 0, 0, null);
    }

    /**
     * 构建一个标识成功带有分页返回数据的对象,对象参考{@link Result}
     * 内部采用 {@link ResultEnum#SUCCESS} 的 code 和 msg
     *
     * @param data  需要返回的数据
     * @param total 总条数
     * @param pages 总页数
     */
    public static <T> Result<T> successPage(T data, long total, long pages) {
        return successPage(data, total, pages, SUCCESS_ENUM.getCode());
    }

    /**
     * 构建一个标识成功带有分页返回数据的对象,对象参考{@link Result}
     * 允许用户自定义 code
     * 内部采用 {@link ResultEnum#SUCCESS} 的 msg
     *
     * @param data  需要返回的数据
     * @param total 总条数
     * @param pages 总页数
     */
    public static <T> Result<T> successPage(T data, long total, long pages, int code) {
        return successPage(data, total, pages, code, SUCCESS_ENUM.getMsg());
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 允许用户自定义 message
     * 内部采用 {@link ResultEnum#SUCCESS} 的 code
     *
     * @param data  需要返回的数据
     * @param total 总条数
     * @param pages 总页数
     */
    public static <T> Result<T> successPage(T data, long total, long pages, String message) {
        return new Result<>(data, SUCCESS_ENUM.getCode(), message, true, total, pages, null);
    }

    /**
     * 构建一个标识成功带有返回数据的对象,对象参考{@link Result}
     * 允许用户自定义 code 和 message
     *
     * @param data  需要返回的数据
     * @param total 总条数
     * @param pages 总页数
     */
    public static <T> Result<T> successPage(T data, long total, long pages, int code, String message) {
        return new Result<>(data, code, message, true, total, pages, null);
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 内部采用 {@link ResultEnum#FAILURE} 的 code 和 msg
     */
    public static <T> Result<T> failure() {
        return failure(FAILURE_ENUM.getCode());
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 允许用户自定义 code
     * 内部采用 {@link ResultEnum#FAILURE} 的 msg
     */
    public static <T> Result<T> failure(Throwable throwable) {
        return failure(FAILURE_ENUM.code, FAILURE_ENUM.msg, throwable);
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 允许用户自定义 code
     * 内部采用 {@link ResultEnum#FAILURE} 的 msg
     */
    public static <T> Result<T> failure(ResultEnum resultEnum) {
        if (resultEnum == null) {
            throw new HandlerException("枚举参数不可为空");
        }
        return failure(resultEnum.code, resultEnum.msg);
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 允许用户自定义 code
     * 内部采用 {@link ResultEnum#FAILURE} 的 msg
     */
    public static <T> Result<T> failure(ResultEnum resultEnum, Throwable throwable) {
        if (resultEnum == null) {
            throw new HandlerException("枚举参数不可为空");
        }
        return failure(resultEnum.code, resultEnum.msg, throwable);
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 允许用户自定义 code
     * 内部采用 {@link ResultEnum#FAILURE} 的 msg
     */
    public static <T> Result<T> failure(int code) {
        return failure(code, FAILURE_ENUM.getMsg());
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 允许用户自定义 code
     * 内部采用 {@link ResultEnum#FAILURE} 的 msg
     */
    public static <T> Result<T> failure(int code, Throwable throwable) {
        return failure(code, FAILURE_ENUM.getMsg(), throwable);
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 允许用户自定义 msg
     * 内部采用 {@link ResultEnum#FAILURE} 的 code
     */
    public static <T> Result<T> failure(String message) {
        return failure(FAILURE_ENUM.getCode(), message);
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 允许用户自定义 msg
     * 内部采用 {@link ResultEnum#FAILURE} 的 code
     */
    public static <T> Result<T> failure(String message, Throwable throwable) {
        return failure(FAILURE_ENUM.getCode(), message, throwable);
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 允许用户自定义 code 和 msg
     */
    public static <T> Result<T> failure(int code, String message) {
        return new Result<>(null, code, message, false, 0, 0, null);
    }

    /**
     * 构建一个标识成功无返回数据的对象{@link Result}
     * 允许用户自定义 code 和 msg
     */
    public static <T> Result<T> failure(int code, String message, Throwable throwable) {
        return new Result<>(null, code, message, false, 0, 0, throwable);
    }
}

